package com.android.measuringimportanceoflectureslides.activities;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.android.measuringimportanceoflectureslides.MainActivity;
import com.android.measuringimportanceoflectureslides.R;
import com.android.measuringimportanceoflectureslides.data.PhotoHandler;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.widget.Toast;

public class TakePicture extends Activity implements SurfaceHolder.Callback {
	private final static String TAG = "MakePhotoActivity";
	private Camera mCamera;
	private Context mContext;
	private SurfaceView mSurfaceView;
	private SurfaceHolder mSurfaceHolder;
	private Camera.Parameters mParameters;
	private PreviewActivity preview;

	public TakePicture(Context context, SurfaceView surfaceView) {
		mContext = context;
		mSurfaceView = surfaceView;
	}

	public void startCapturing() {
//		preview = new Preview(mContext);
//		mParameters = preview.getParameters();
		
		// ******* Open Camera **************
		openCamera();

		// ******* Take picture for loop *************
		try {
			for (int i = 0; i < 20; i++) {
				
				if(MainActivity.debugCamera == 1){
					Toast.makeText(mContext, "Take picture", Toast.LENGTH_SHORT).show();
				}
				// ******** autoFocus is called, and if the camera is focused then picture taken is called
				autofocus();
	
				// ******** Picture is taken ******* 
//				mCamera.takePicture(null, null, new PhotoHandler(mContext));
//				setSurface();
				
				try {
					if(MainActivity.debugCamera == 1){
						Toast.makeText(mContext, "Thread Sleeps 4 second", Toast.LENGTH_SHORT).show();
					}
					
					// ********* Thread sleeps 2 Seconds ************
					Thread.sleep(4000);
				} catch (InterruptedException e) {
					e.printStackTrace();
					Toast.makeText(this, "error: " + e, Toast.LENGTH_LONG)
							.show();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(mContext, "error: " + e,
					Toast.LENGTH_LONG).show();
		}
	}

	public void stopCapturing() {
		if (mCamera != null) {
			mCamera.stopPreview();
			mCamera.release();
			mCamera = null;
		}
	}

	private void openCamera() {
		// check if a camera is available
		if (!mContext.getPackageManager()
				.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
			Toast.makeText(mContext, "No camera on this device", Toast.LENGTH_LONG).show();
		} else {
			mCamera = Camera.open();
			
			// ******* Save the camera Parameters ********+
			mParameters = mCamera.getParameters();
			
			mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
			mCamera.setParameters(mParameters);
//			SurfaceView view = new SurfaceView(mContext);
//			try {
//				mCamera.setPreviewDisplay(view.getHolder());
//				mCamera.startPreview();
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
			
			// ********** Define the rect where the it will be focused *************
			setMeteringAreas();
			setFocusAreas();
			
			// ********** Set Surface *************
			setSurface();
		}
	}

	private void setSurface() {
		mSurfaceHolder = mSurfaceView.getHolder();
		mSurfaceHolder.addCallback(this);
		mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		surfaceCreated(mSurfaceHolder);
		
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        
	    // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        mParameters.setPreviewSize(width, height);
        mCamera.setParameters(mParameters);
		try {
			mCamera.setPreviewDisplay(mSurfaceHolder);
			mCamera.startPreview();
		} catch (IOException e) {
			 Log.d(TAG, "Error starting camera preview: " + e.getMessage());
		}

	}

	public void surfaceCreated(SurfaceHolder surfaceHolder) {
		try {
			mCamera.setPreviewDisplay(mSurfaceHolder);
			mCamera.startPreview();
		} catch (IOException e) {
			Log.d(TAG, "IO Exception", e);
		}
	}

	public void surfaceDestroyed(SurfaceHolder arg0) {
		stopCapturing();		
	}
	
	private void autofocus(){
		if (mParameters.getSupportedFocusModes().contains(
				Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
					mParameters.setFocusMode(
							Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
					mCamera.autoFocus(new AutoFocusCallback() {
						public void onAutoFocus(boolean success, Camera camera) {
							// ****** takePicture is called *******
							camera.takePicture(null, null, new PhotoHandler(mContext));
							setSurface();
							Log.d(TAG, "AutoFocus: " + (success ? "Succeeded" : "Failed"));
						}
					});
		}
	}
	
	private void getDistance(){
		float[] focusDistances = new float[3];
		mParameters.getFocusDistances(focusDistances);
		float near = focusDistances[Camera.Parameters.FOCUS_DISTANCE_NEAR_INDEX];
		float far = focusDistances[Camera.Parameters.FOCUS_DISTANCE_FAR_INDEX];
		float optimal = focusDistances[Camera.Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX];
	}
	
	private int getFocusAreas(){
		return mParameters.getMaxNumFocusAreas();
	}
	
	private void setMeteringAreas(){
		
		// ***********  http://developer.android.com/guide/topics/media/camera.html ********
		
		if (mParameters.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
		    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

//		    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
//		    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
//		    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
//		    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
		    
		    Rect areaRect1 = new Rect(-100, -800, 100, 600);  // specify an area in upper right of image
		    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 40%
		    mParameters.setMeteringAreas(meteringAreas);
		}
		else {
			if (MainActivity.debugCamera == 1){
				Toast.makeText(mContext, "MAx SetMeterAreas: "+ mParameters.getMaxNumMeteringAreas(), Toast.LENGTH_SHORT).show();
				Log.d(TAG, "MAx SetMeterAreas: "+ mParameters.getMaxNumMeteringAreas());
			}
		}
		
		mCamera.setParameters(mParameters);
	}
	private void setFocusAreas(){
		
		// ***********  http://developer.android.com/guide/topics/media/camera.html ********
		
		if (mParameters.getMaxNumFocusAreas() > 0){ // check that metering areas are supported
			List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
			
//		    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
//		    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
//		    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
//		    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
			
			Rect areaRect1 = new Rect(-100, -800, 100, 600);  // specify an area in upper right of image
			focusAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 40%
			mParameters.setFocusAreas(focusAreas);
		}
		else {
			if (MainActivity.debugCamera == 1){
				Toast.makeText(mContext, "MAx SetFocusAreas: "+ mParameters.getMaxNumFocusAreas(), Toast.LENGTH_SHORT).show();
				Log.d(TAG, "MAx SetFocusAreas: "+ mParameters.getMaxNumFocusAreas());
			}
		}
		
		mCamera.setParameters(mParameters);
	}
	
	// ************** With this code you can manipulate each preview frame (book professional android 4 application, page 653)
	public void manipulateEachFrame(){
		mCamera.setPreviewCallback(new PreviewCallback() {
			public void onPreviewFrame(byte[] data, Camera camera) {
				int quality = 60;
				Size previewSize = camera.getParameters().getPreviewSize();
				YuvImage image = new YuvImage(data, ImageFormat.NV21,
						previewSize.width, previewSize.height, null);
				ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
				image.compressToJpeg(new Rect(0, 0, previewSize.width,
						previewSize.height), quality, outputStream);
				// TODO Do something with the preview image.
			}
		});
	}
}
